package com.iotechn.unimall.admin.api.warehouseLoss;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.iotechn.unimall.biz.service.goods.GoodsBizService;
import com.iotechn.unimall.core.exception.AdminServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.core.exception.ServiceException;
import com.iotechn.unimall.core.exception.ServiceExceptionDefinition;
import com.iotechn.unimall.data.domain.*;
import com.iotechn.unimall.data.dto.AdminDTO;
import com.iotechn.unimall.data.dto.warehouse.WarehouseLossDTO;
import com.iotechn.unimall.data.dto.warehouse.WarehouseLossGoodsDTO;
import com.iotechn.unimall.data.dto.warehouse.WarehouseLossOperLogDTO;
import com.iotechn.unimall.data.mapper.*;
import com.iotechn.unimall.data.model.Page;
import com.iotechn.unimall.data.util.SessionUtil;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class WarehouseLossServiceImpl implements WarehouseLossService {
    final static String LOSS_NO_PRE = "SH";//损耗
    @Autowired
    private WarehouseLossMapper warehouseLossMapper;
    @Autowired
    private WarehouseLossGoodsMapper warehouseLossGoodsMapper;
    @Autowired
    private WarehouseLossOperLogMapper warehouseLossOperLogMapper;
    @Autowired
    private WarehouseMapper warehouseMapper;
    @Autowired
    private WarehouseGoodsMapper warehouseGoodsMapper;
    @Autowired
    private WarehouseOperLogMapper warehouseOperLogMapper;
    @Autowired
    private GoodsBizService goodsBizService;

    @Override
    public Page<WarehouseLossDO> list(Integer page, Integer limit, Long adminId, String lossCheckNo,
                                      String skuSearch,
                                      String checkStartTime,
                                      String checkEndTime, String lossCheckState) throws ServiceException {
        Wrapper<WarehouseLossDO> wrapper = new EntityWrapper<WarehouseLossDO>();
        if (!StringUtils.isEmpty(lossCheckNo)) {
            wrapper.like("loss_check_no", lossCheckNo);
        }
        if (!StringUtils.isEmpty(lossCheckState)) {
            wrapper.eq("loss_check_state", lossCheckState);
        }
        //时间范围搜索
        if (!StringUtils.isEmpty(checkStartTime)) {
            wrapper.gt("gmt_create", checkStartTime);
        }
        if (!StringUtils.isEmpty(checkEndTime)) {
            wrapper.le("gmt_create", checkEndTime);
        }
        List<Long> orderIds = new LinkedList<>();
        if (!StringUtils.isEmpty(skuSearch)) {
            List<WarehouseLossGoodsDO> orderSkus = warehouseLossGoodsMapper.selectList(new EntityWrapper<WarehouseLossGoodsDO>()
                    .like("goods_bar_code", skuSearch).or().like("spu_name", skuSearch).or().like("sku_name", skuSearch));

            if (CollectionUtils.isEmpty(orderSkus)) {
                return new Page<>(new ArrayList<>(), page, limit, 0L);
            }
            orderIds = orderSkus.stream().map(WarehouseLossGoodsDO::getLossCheckId).distinct().collect(Collectors.toList());
            wrapper.in(!CollectionUtils.isEmpty(orderIds), "id", orderIds);
        }
        wrapper.orderBy("id", false);
        Integer count = warehouseLossMapper.selectCount(wrapper);
        List<WarehouseLossDO> warehouseLossDOS = warehouseLossMapper.selectPage(new RowBounds((page - 1) * limit, limit), wrapper);
        warehouseLossDOS.forEach(item -> {
            List<WarehouseLossGoodsDO> skus = warehouseLossGoodsMapper.selectList(new EntityWrapper<WarehouseLossGoodsDO>()
                    .eq("loss_check_id", item.getId()));
            item.setSkus(skus);
        });
        return new Page<>(warehouseLossDOS, page, limit, count);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String create(WarehouseLossDTO warehouseLossDTO, Long adminId) throws ServiceException {
        //添加损耗单
        Date now = new Date();
        WarehouseLossDO warehouseLossDO = new WarehouseLossDO();
        BeanUtils.copyProperties(warehouseLossDTO, warehouseLossDO);
        warehouseLossDO.setAdminId(adminId);
        warehouseLossDO.setLossCheckState(0);//待确认
        warehouseLossDO.setLossCheckCount(warehouseLossDTO.getTotal());
        warehouseLossDO.setLossCheckAmount((long) (warehouseLossDTO.getTotalPrice() * 100));
        warehouseLossDO.setGmtUpdate(now);
        warehouseLossDO.setGmtCreate(now);
        warehouseLossDO.setLossCheckTime(now);
        warehouseLossDO.setLossCheckNo(LOSS_NO_PRE + System.currentTimeMillis());//自动编号
        //操作人真实姓名
        AdminDTO adminDTO = SessionUtil.getAdmin();
        if (adminDTO != null) {
            warehouseLossDO.setLossCheckUser(adminDTO.getRealname());
            warehouseLossDO.setLossCheckId(adminDTO.getId());
            warehouseLossDO.setAdminRealname(adminDTO.getRealname());
            warehouseLossDO.setAdminUsername(adminDTO.getUsername());
        }
        if (warehouseLossMapper.insert(warehouseLossDO) > 0) {
            for (WarehouseLossGoodsDTO warehouseLossGoodsDTO : warehouseLossDTO.getWarehouseLossGoodsDTOS()) {
                WarehouseLossGoodsDO warehouseGoodsDO = new WarehouseLossGoodsDO();
                BeanUtils.copyProperties(warehouseLossGoodsDTO, warehouseGoodsDO);
                warehouseGoodsDO.setGoodsBarCode(warehouseLossGoodsDTO.getBarCode());
                warehouseGoodsDO.setGoodsImg(warehouseLossGoodsDTO.getImg());
                warehouseGoodsDO.setGoodsUnit(warehouseLossGoodsDTO.getUnit());
                warehouseGoodsDO.setLossCheckId(warehouseLossDO.getId());
                warehouseGoodsDO.setLossType(warehouseLossDO.getLossType());
                warehouseGoodsDO.setWarehouseId(warehouseLossDO.getWarehouseId());
                warehouseGoodsDO.setLossCheckGoodsAmount(warehouseLossGoodsDTO.getAverPrice() == null || warehouseLossGoodsDTO.getAverPrice() == 0 ? 0 : (long) (warehouseLossGoodsDTO.getAverPrice() * 100));
                warehouseGoodsDO.setLossCheckPreGoodsNum(warehouseLossGoodsDTO.getWarehouseSkuNum());
                warehouseGoodsDO.setLossCheckAftGoodsNum(warehouseLossGoodsDTO.getWarehouseSkuNum() - warehouseLossGoodsDTO.getLossCheckGoodsNum());
                warehouseLossGoodsMapper.insert(warehouseGoodsDO);
            }
            //插入操作表
            //操作人真实姓名
            if (adminDTO != null) {
                insertOperLog(warehouseLossDO, adminDTO);
            }
            return "ok";
        }
        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String update(WarehouseLossDTO warehouseLossDTO, Long adminId) throws ServiceException {
        Long id = warehouseLossDTO.getId();
        if (id == null) {
            return "fail";
        }
        //添加损耗单
        Date now = new Date();
        WarehouseLossDO warehouseLossDO = new WarehouseLossDO();
        BeanUtils.copyProperties(warehouseLossDTO, warehouseLossDO);
        warehouseLossDO.setAdminId(adminId);
        warehouseLossDO.setLossCheckCount(warehouseLossDTO.getTotal());
        warehouseLossDO.setLossCheckAmount((long) (warehouseLossDTO.getTotalPrice() * 100));
        warehouseLossDO.setGmtUpdate(now);
        //删除损耗-商品
        warehouseLossGoodsMapper.delete(new EntityWrapper<WarehouseLossGoodsDO>()
                .eq("warehouse_id", warehouseLossDTO.getWarehouseId())
                .eq("loss_check_id", warehouseLossDTO.getId()));
        //操作人真实姓名
        AdminDTO adminDTO = SessionUtil.getAdmin();
        if (adminDTO != null) {
            warehouseLossDO.setLossCheckUser(adminDTO.getRealname());
            warehouseLossDO.setLossCheckId(adminDTO.getId());
            warehouseLossDO.setAdminRealname(adminDTO.getRealname());
            warehouseLossDO.setAdminUsername(adminDTO.getUsername());
        }
        if (warehouseLossMapper.updateById(warehouseLossDO) > 0) {
            for (WarehouseLossGoodsDTO warehouseLossGoodsDTO : warehouseLossDTO.getWarehouseLossGoodsDTOS()) {
                WarehouseLossGoodsDO warehouseGoodsDO = new WarehouseLossGoodsDO();
                BeanUtils.copyProperties(warehouseLossGoodsDTO, warehouseGoodsDO);
                warehouseGoodsDO.setGoodsBarCode(warehouseLossGoodsDTO.getBarCode());
                warehouseGoodsDO.setGoodsImg(warehouseLossGoodsDTO.getImg());
                warehouseGoodsDO.setGoodsUnit(warehouseLossGoodsDTO.getUnit());
                warehouseGoodsDO.setLossCheckId(warehouseLossDO.getId());
                warehouseGoodsDO.setLossType(warehouseLossDO.getLossType());
                warehouseGoodsDO.setWarehouseId(warehouseLossDO.getWarehouseId());
                warehouseGoodsDO.setLossCheckGoodsAmount(warehouseLossGoodsDTO.getAverPrice() == null || warehouseLossGoodsDTO.getAverPrice() == 0 ? 0 : (long) (warehouseLossGoodsDTO.getAverPrice() * 100));
                warehouseGoodsDO.setLossCheckPreGoodsNum(warehouseLossGoodsDTO.getWarehouseSkuNum());
                warehouseGoodsDO.setLossCheckAftGoodsNum(warehouseLossGoodsDTO.getWarehouseSkuNum() - warehouseLossGoodsDTO.getLossCheckGoodsNum());
                warehouseLossGoodsMapper.insert(warehouseGoodsDO);
            }
            //插入操作表
            //操作人真实姓名
            if (adminDTO != null) {
                insertOperLog(warehouseLossDO, adminDTO);
            }
            return "ok";
        }

        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String delete(Long id, Long adminId) throws ServiceException {
        if (warehouseLossMapper.deleteById(id) > 0) {
            return "ok";
        }
        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);

    }

    @Override
    public WarehouseLossDTO detail(Long id, Long adminId) throws ServiceException {
        WarehouseLossDO warehouseLossDO = warehouseLossMapper.selectById(id);
        WarehouseLossDTO warehouseLossDTO = new WarehouseLossDTO();
        BeanUtils.copyProperties(warehouseLossDO, warehouseLossDTO);
        warehouseLossDTO.setLossCheckConfirmId(warehouseLossDO.getLossCheckConfirmId());
        warehouseLossDTO.setLossCheckConfirmRealname(warehouseLossDO.getLossCheckConfirmRealname());
        warehouseLossDTO.setLossCheckConfirmUsername(warehouseLossDO.getLossCheckConfirmUsername());
        WarehouseDO warehouseDO = warehouseMapper.selectById(warehouseLossDO.getWarehouseId());
        if (warehouseDO != null) {
            warehouseLossDTO.setWarehouseName(warehouseDO.getWarehouseName());
        }
        warehouseLossDTO.setLossCheckAmount(Float.valueOf(warehouseLossDO.getLossCheckAmount()) / 100);
//通过盘点单获取商品
        List<WarehouseLossGoodsDTO> warehouseLossGoodsDTOS = warehouseLossGoodsMapper.querySkusByPara(null, id, null, null, null);
        warehouseLossDTO.setWarehouseLossGoodsDTOS(warehouseLossGoodsDTOS);

        //操作日志
        List<WarehouseLossOperLogDTO> warehouseLossOperLogDTOS = warehouseLossOperLogMapper.listLogsByPara(id);
        warehouseLossDTO.setWarehouseLossOperLogDTOS(warehouseLossOperLogDTOS);
        return warehouseLossDTO;
    }

    @Override
    public List<WarehouseLossDO> listAll() throws ServiceException {
        return warehouseLossMapper.selectList(new EntityWrapper<WarehouseLossDO>());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String confirm(Long lossCheckId, Long adminId) throws ServiceException {
        if (lossCheckId == null || "".equals(lossCheckId)) {
            return "fail";
        }
        WarehouseLossDO warehouseLossDO = warehouseLossMapper.selectById(lossCheckId);
        if (warehouseLossDO == null) {
            return "fail";
        }
        if(warehouseLossDO.getLossCheckState().intValue() == 1){
            throw new AdminServiceException(new ServiceExceptionDefinition(500, "当前损耗单已审核"));
        }
        WarehouseDO warehouseDO = warehouseMapper.selectById(warehouseLossDO.getWarehouseId());
        Date now = new Date();
        warehouseLossDO.setGmtUpdate(now);
        AdminDTO adminDTO = SessionUtil.getAdmin();
        if (adminDTO != null) {
            warehouseLossDO.setLossCheckConfirmId(adminDTO.getId());
            warehouseLossDO.setLossCheckConfirmRealname(adminDTO.getRealname());
            warehouseLossDO.setLossCheckConfirmUsername(adminDTO.getUsername());
            warehouseLossDO.setLossCheckConfirmTime(now);
        }
        warehouseLossDO.setLossCheckState(1);//已确认
        if (warehouseLossMapper.updateById(warehouseLossDO) > 0) {
            List<WarehouseLossGoodsDO> warehouseLossGoodsDOS = warehouseLossGoodsMapper.selectList(new EntityWrapper<WarehouseLossGoodsDO>()
                    .eq("loss_check_id", warehouseLossDO.getId())
                    .eq("warehouse_id", warehouseLossDO.getWarehouseId()));
            for (WarehouseLossGoodsDO warehouseLossGoodsDO : warehouseLossGoodsDOS) {
                //更新库存商品数量
//                List<WarehouseGoodsDO> warehouseGoodsDOS = warehouseGoodsMapper.selectList(new EntityWrapper<WarehouseGoodsDO>().eq("warehouse_id", warehouseLossDO.getWarehouseId())
//                        .eq("sku_bar_code", warehouseLossGoodsDO.getGoodsBarCode()));
                List<WarehouseGoodsDO> warehouseGoodsDOS = warehouseGoodsMapper.selectList(new EntityWrapper<WarehouseGoodsDO>().eq("warehouse_id", warehouseLossDO.getWarehouseId())
                        .eq("sku_id", warehouseLossGoodsDO.getSkuId()));
                WarehouseGoodsDO warehouseGoodsDO = null;
                Float changeSkuStock = warehouseLossGoodsDO.getLossCheckGoodsNum();
                Float totalSkuStock = 0.000f;
                if (!CollectionUtils.isEmpty(warehouseGoodsDOS)) {
                    warehouseGoodsDO = warehouseGoodsDOS.get(0);
                    if (warehouseGoodsDO != null) {
                        totalSkuStock = warehouseGoodsDO.getWarehouseSkuStock() - changeSkuStock;//总库存-损耗数量
                        warehouseGoodsDO.setWarehouseSkuStock(totalSkuStock);
                        warehouseGoodsDO.setGmtUpdate(now);
                        warehouseGoodsDO.setWarehouseName(warehouseDO.getWarehouseName());
                        warehouseGoodsMapper.updateById(warehouseGoodsDO);
                    }
                }
                //更新仓库-商品操作
                WarehouseOperLogDO warehouseOperLogDO = new WarehouseOperLogDO();
                warehouseOperLogDO.setGmtCreate(now);
                warehouseOperLogDO.setGmtUpdate(now);
                warehouseOperLogDO.setChangeSkuStock(warehouseLossGoodsDO.getLossCheckGoodsNum());
                warehouseOperLogDO.setAdminId(adminId);
                warehouseOperLogDO.setType(4);//4代表损耗
                warehouseOperLogDO.setSkuId(warehouseLossGoodsDO.getSkuId());
                warehouseOperLogDO.setWarehouseSkuStock(totalSkuStock);
                warehouseOperLogDO.setWarehouseId(warehouseLossDO.getWarehouseId());
                warehouseOperLogDO.setSpuName(warehouseLossGoodsDO.getSpuName());
                warehouseOperLogDO.setSpuId(warehouseGoodsDO.getSpuId());
                warehouseOperLogDO.setWarehouseName(warehouseDO.getWarehouseName());
                warehouseOperLogDO.setSkuName(warehouseLossGoodsDO.getSkuName());
                warehouseOperLogDO.setSkuNo(warehouseLossGoodsDO.getGoodsBarCode());
                warehouseOperLogDO.setOrderNo(warehouseLossDO.getLossCheckNo());
                warehouseOperLogDO.setOrderId(warehouseLossDO.getId());
                warehouseOperLogDO.setAdminName(adminDTO.getRealname());
                warehouseOperLogMapper.insert(warehouseOperLogDO);
                //更新总库存
                // goodsBizService.updateGoodsStockByPara(warehouseLossGoodsDO.getSkuId(), warehouseLossGoodsDO.getGoodsBarCode(), GoodsEntryType.LOSS.getCode(), warehouseLossGoodsDO.getLossCheckGoodsNum());
            }


            //插入操作表
            //操作人真实姓名
            if (adminDTO != null) {
                insertOperLog(warehouseLossDO, adminDTO);
            }
            return "ok";
        }
        throw new AdminServiceException(ExceptionDefinition.ADMIN_UNKNOWN_EXCEPTION);
    }

    /**
     * 插入操作日志 损耗-记录
     *
     * @throws Exception
     */
    private void insertOperLog(WarehouseLossDO warehouseLossDO, AdminDTO adminDTO) {
        Date now = new Date();
        WarehouseLossOperLogDO warehouseLossOperLogDO = new WarehouseLossOperLogDO();
        warehouseLossOperLogDO.setLossCheckId(warehouseLossDO.getId());
        warehouseLossOperLogDO.setGmtCreate(now);
        warehouseLossOperLogDO.setAdminId(adminDTO.getId());
        warehouseLossOperLogDO.setLossCheckInfo(warehouseLossDO.getLossCheckInfo());
        warehouseLossOperLogDO.setGmtUpdate(now);
        warehouseLossOperLogDO.setLossCheckUsername(warehouseLossDO.getAdminUsername());
        warehouseLossOperLogDO.setLossCheckTime(warehouseLossDO.getLossCheckTime());
        warehouseLossOperLogDO.setLossCheckUser(warehouseLossDO.getLossCheckUser());
        warehouseLossOperLogDO.setLossCheckNo(warehouseLossDO.getLossCheckNo());
        warehouseLossOperLogDO.setLossCheckState(warehouseLossDO.getLossCheckState());
        warehouseLossOperLogDO.setWarehouseId(warehouseLossDO.getWarehouseId());
        warehouseLossOperLogDO.setLossCheckAmount(warehouseLossDO.getLossCheckAmount());
        warehouseLossOperLogDO.setLossCheckCount(warehouseLossDO.getLossCheckCount());
        warehouseLossOperLogDO.setLossType(warehouseLossDO.getLossType());
        warehouseLossOperLogDO.setLossCheckNo(warehouseLossDO.getLossCheckNo());
        warehouseLossOperLogMapper.insert(warehouseLossOperLogDO);
    }
}